package handlers

import (
	"context"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	integrationv1 "github.com/devops-smartbot/devops-smartbot/proto/gen/go/integration/v1"
	"go.uber.org/zap"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

type IntegrationHandler struct {
	client integrationv1.IntegrationServiceClient
	logger *zap.Logger
}

func NewIntegrationHandler(integrationServiceAddr string, logger *zap.Logger) (*IntegrationHandler, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	conn, err := grpc.DialContext(ctx, integrationServiceAddr, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithBlock())
	if err != nil {
		return nil, err
	}

	client := integrationv1.NewIntegrationServiceClient(conn)
	return &IntegrationHandler{
		client: client,
		logger: logger,
	}, nil
}

// Jira Endpoints

// @Summary Sync ticket to Jira
// @Router /api/integrations/jira/sync-ticket [post]
func (h *IntegrationHandler) SyncTicketToJira(c *gin.Context) {
	var req struct {
		TicketID   string `json:"ticket_id" binding:"required"`
		ProjectKey string `json:"project_key"`
		IssueType  string `json:"issue_type"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	resp, err := h.client.SyncTicketToJira(c.Request.Context(), &integrationv1.SyncTicketToJiraRequest{
		TicketId:   req.TicketID,
		ProjectKey: req.ProjectKey,
		IssueType:  req.IssueType,
	})

	if err != nil {
		h.logger.Error("Failed to sync ticket to Jira", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success":    resp.Success,
		"message":    resp.Message,
		"jira_issue": resp.JiraIssue,
	})
}

// @Summary Sync Jira issue to ticket
// @Router /api/integrations/jira/sync-issue [post]
func (h *IntegrationHandler) SyncJiraIssue(c *gin.Context) {
	var req struct {
		JiraKey string `json:"jira_key" binding:"required"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	resp, err := h.client.SyncJiraIssue(c.Request.Context(), &integrationv1.SyncJiraIssueRequest{
		JiraKey: req.JiraKey,
	})

	if err != nil {
		h.logger.Error("Failed to sync Jira issue", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success":   resp.Success,
		"message":   resp.Message,
		"ticket_id": resp.TicketId,
	})
}

// @Summary Get Jira configuration
// @Router /api/integrations/jira/config [get]
func (h *IntegrationHandler) GetJiraConfig(c *gin.Context) {
	resp, err := h.client.GetJiraConfig(c.Request.Context(), &integrationv1.GetJiraConfigRequest{})
	if err != nil {
		h.logger.Error("Failed to get Jira config", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"config": resp.Config,
	})
}

// @Summary Update Jira configuration
// @Router /api/integrations/jira/config [put]
func (h *IntegrationHandler) UpdateJiraConfig(c *gin.Context) {
	var req struct {
		BaseURL          string `json:"base_url" binding:"required"`
		Username         string `json:"username" binding:"required"`
		APIToken         string `json:"api_token" binding:"required"`
		ProjectKey       string `json:"project_key" binding:"required"`
		DefaultIssueType string `json:"default_issue_type"`
		AutoSync         bool   `json:"auto_sync"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	resp, err := h.client.UpdateJiraConfig(c.Request.Context(), &integrationv1.UpdateJiraConfigRequest{
		BaseUrl:          req.BaseURL,
		Username:         req.Username,
		ApiToken:         req.APIToken,
		ProjectKey:       req.ProjectKey,
		DefaultIssueType: req.DefaultIssueType,
		AutoSync:         req.AutoSync,
	})

	if err != nil {
		h.logger.Error("Failed to update Jira config", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success": resp.Success,
		"message": resp.Message,
		"config":  resp.Config,
	})
}

// PagerDuty Endpoints

// @Summary Create PagerDuty incident
// @Router /api/integrations/pagerduty/incidents [post]
func (h *IntegrationHandler) CreatePagerDutyIncident(c *gin.Context) {
	var req struct {
		Title       string `json:"title" binding:"required"`
		Description string `json:"description"`
		Urgency     string `json:"urgency"`
		AlertID     string `json:"alert_id"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	resp, err := h.client.CreatePagerDutyIncident(c.Request.Context(), &integrationv1.CreatePagerDutyIncidentRequest{
		Title:       req.Title,
		Description: req.Description,
		Urgency:     req.Urgency,
		AlertId:     req.AlertID,
	})

	if err != nil {
		h.logger.Error("Failed to create PagerDuty incident", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success":  resp.Success,
		"message":  resp.Message,
		"incident": resp.Incident,
	})
}

// @Summary Get PagerDuty incident
// @Router /api/integrations/pagerduty/incidents/:id [get]
func (h *IntegrationHandler) GetPagerDutyIncident(c *gin.Context) {
	incidentID := c.Param("id")

	resp, err := h.client.GetPagerDutyIncident(c.Request.Context(), &integrationv1.GetPagerDutyIncidentRequest{
		IncidentId: incidentID,
	})

	if err != nil {
		h.logger.Error("Failed to get PagerDuty incident", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"incident": resp.Incident,
	})
}

// @Summary Update PagerDuty incident
// @Router /api/integrations/pagerduty/incidents/:id [put]
func (h *IntegrationHandler) UpdatePagerDutyIncident(c *gin.Context) {
	incidentID := c.Param("id")

	var req struct {
		Status         string `json:"status"`
		ResolutionNote string `json:"resolution_note"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	resp, err := h.client.UpdatePagerDutyIncident(c.Request.Context(), &integrationv1.UpdatePagerDutyIncidentRequest{
		IncidentId:     incidentID,
		Status:         req.Status,
		ResolutionNote: req.ResolutionNote,
	})

	if err != nil {
		h.logger.Error("Failed to update PagerDuty incident", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success":  resp.Success,
		"message":  resp.Message,
		"incident": resp.Incident,
	})
}

// @Summary Get PagerDuty configuration
// @Router /api/integrations/pagerduty/config [get]
func (h *IntegrationHandler) GetPagerDutyConfig(c *gin.Context) {
	resp, err := h.client.GetPagerDutyConfig(c.Request.Context(), &integrationv1.GetPagerDutyConfigRequest{})
	if err != nil {
		h.logger.Error("Failed to get PagerDuty config", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"config": resp.Config,
	})
}

// @Summary Update PagerDuty configuration
// @Router /api/integrations/pagerduty/config [put]
func (h *IntegrationHandler) UpdatePagerDutyConfig(c *gin.Context) {
	var req struct {
		APIKey             string `json:"api_key" binding:"required"`
		ServiceID          string `json:"service_id" binding:"required"`
		EscalationPolicyID string `json:"escalation_policy_id"`
		AutoCreateIncident bool   `json:"auto_create_incident"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	resp, err := h.client.UpdatePagerDutyConfig(c.Request.Context(), &integrationv1.UpdatePagerDutyConfigRequest{
		ApiKey:             req.APIKey,
		ServiceId:          req.ServiceID,
		EscalationPolicyId: req.EscalationPolicyID,
		AutoCreateIncident: req.AutoCreateIncident,
	})

	if err != nil {
		h.logger.Error("Failed to update PagerDuty config", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success": resp.Success,
		"message": resp.Message,
		"config":  resp.Config,
	})
}

// Generic Endpoints

// @Summary List all integrations
// @Router /api/integrations [get]
func (h *IntegrationHandler) ListIntegrations(c *gin.Context) {
	resp, err := h.client.ListIntegrations(c.Request.Context(), &integrationv1.ListIntegrationsRequest{})
	if err != nil {
		h.logger.Error("Failed to list integrations", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"integrations": resp.Integrations,
	})
}

// @Summary Test integration connection
// @Router /api/integrations/test [post]
func (h *IntegrationHandler) TestIntegration(c *gin.Context) {
	var req struct{
		Type string `json:"type" binding:"required"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	var integrationType integrationv1.IntegrationType
	switch req.Type {
	case "jira":
		integrationType = integrationv1.IntegrationType_INTEGRATION_TYPE_JIRA
	case "pagerduty":
		integrationType = integrationv1.IntegrationType_INTEGRATION_TYPE_PAGERDUTY
	default:
		c.JSON(http.StatusBadRequest, gin.H{"error": "Unknown integration type"})
		return
	}

	resp, err := h.client.TestIntegration(c.Request.Context(), &integrationv1.TestIntegrationRequest{
		Type: integrationType,
	})

	if err != nil {
		h.logger.Error("Failed to test integration", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success": resp.Success,
		"message": resp.Message,
	})
}
